﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TANKWAR_alpha
{
    /*
     * the central class of the game's running
     */ 
    class Game:GameAbstract
    {
        private Collision collision;    //collision as a member to make a judgement of some crashes
        private bool gamestate;      //judge whether the current game is running or over

        private GameGDI gameEngine;

        public bool VictoryOrDie;

        public Game (Collision co)
        {
            collision=co;
            gameEngine = collision.GameEngine;

            /*
           * create the player's tank
           */
            
        }
        public override void Prepare(byte mapChoice)
        {
            //initial playertank
            this.GameEngine.MyTank = new TankPlayer(0, Constant.clientHeight - Constant.tankHeight, this.GameEngine);

            //Wall  initiation
            Wall w;
            for (int i = 0; i < 26; i++)
            {
                for (int j = 0; j < 26; j++)
                {
                    if (Constant.map[mapChoice-1][i][j]!= 9)
                    {
                        w = new Wall(i * Constant.CanvasUnit, j*Constant.CanvasUnit,Constant.map[mapChoice-1][i][j]);
                        gameEngine.Walls.Add(w);
                    }
                }
            }
        

        }
        public override void Run()
        {
            UpdateChangePosition();
            if(gamestate!=false)
                Update();
        }

        private void  UpdateChangePosition()
        {
            /*
             *  this function is very essential, it's because of its exsitence that all pictures(objects)
             *  presented on the screen can have the animation. The game's Run() call it 
             *  every time in the circulation so as to update all varieties of objects' position 
             *  and determine which get a collision with another, then end up its life by 
             *  seting the boolean of its Life property to false in attempt to delete or clear these
             *  'dead' element from the list which prompts the GC(abbreviation of Garbage 
             *  Collection) get these memory of no reference;
             *  
             *  the order of updating:
             *   1.PlayerBullets
             *   2.RobotBullets
             *   3.RobotTanks
             *   4.PlayerTank
             *   5.robot's AI and shooting
             *   6.robotBoss
             */

            //------------update playerBullets' positions------------------
            foreach(Bullet b in gameEngine.PlayerBullets)
            {
                if (!b.Life)
                    continue;

                //judge whether crossing the boundary
                if (b.Left < 0 || b.Left + Constant.bombWidth > Constant.clientWidth || b.Top < 0 || b.Top + Constant.bombHeight > Constant.clientHeight)
                {
                    b.Life = false;
                }
                else if (collision.IsPlayerBulletsHitTankRobot(b))  //judge whether hiting the RobotTanks
                {
                    Explorer explode = new Explorer(b.Left, b.Top-40,0);
                    gameEngine.Explodes.Add(explode);
                    b.Life = false;
                    PlayMusic.Play(@"Music\ExplodeSound.wav");
                }
                else if (collision.IsPlayerBulletHitRobotBullets(b)) //judge whether hiting the RobotBullet
                {
                    b.Life = false;
                }
                else      //judge whether hitting the Wall
                {
                    int f = collision.IsPlayerBulletsHitReWall(b);
                    if (f != 0)
                    {
                        Explorer explode = new Explorer(b.Left, b.Top, 1);
                        gameEngine.Explodes.Add(explode);
                        b.Life = false;
                        if (f == 2)
                        {
                            VictoryOrDie = false;
                            gamestate = false;
                        }
                    }
                }

                if (b.Life)
                    b.BulletMove();
            }

            //------------update RobotBullets' positions------------------
            foreach (Bullet b in gameEngine.RobotBullets)
            {
                if (!b.Life)
                    continue;

                //judge whether crossing the boundary
                if (b.Left < 0 || b.Left + Constant.bombWidth > Constant.clientWidth || b.Top < 0 || b.Top + Constant.bombHeight > Constant.clientHeight)
                {
                    b.Life = false;
                }
                else if (collision.IsRobotBulletsHitTankPlayer(b))  //judge whether hiting mytank
                {
                    Explorer explode = new Explorer(b.Left, b.Top, 1);
                    gameEngine.Explodes.Add(explode);
                    b.Life = false;
                    gameEngine.MyTank.Life = false;
                    gamestate = false;
                    VictoryOrDie = false;
                    return;

                }
                else if (collision.IsRobotBulletsHitPlayerBullets(b)) //judge whether hiting the PlayerBullet
                {
                    b.Life = false;
                }
                else   //judge whether hitting the Wall
                {
                    int f = collision.IsPlayerBulletsHitReWall(b);
                    if (f != 0)
                    {
                        Explorer explode = new Explorer(b.Left, b.Top, 1);
                        gameEngine.Explodes.Add(explode);
                        b.Life = false;
                        if (f == 2)
                        {
                            VictoryOrDie = false;
                            gamestate = false;
                        }
                    }
                }

                if (b.Life)
                    b.BulletMove();
            }

            //-----------------update RobotTank's Position-------------------
            foreach(TankRobot taR in gameEngine.TankRobots)
            {
                if (!taR.Life)
                    continue;

                if(collision.IsTankHitBullets(taR))
                {
                    Explorer explode = new Explorer(taR.Left-10, taR.Top-10,0);
                    gameEngine.Explodes.Add(explode);
                    //PlayMusic.Play(@"Music\ExplodeSound.wav");
                    taR.Life = false;
                }

                if (taR.Life)
                    taR.MoveByRobotTank();
            }

            //-----------------update playertank's Position-----------------------
            if (collision.IsTankHitBullets(gameEngine.MyTank))
            {
                gameEngine.MyTank.Life = false;
                gamestate = false;
                return;
            }

            //------------update Robot's AI and shooting---------------------
            foreach (TankRobot taR in this.GameEngine.TankRobots)
            {
                if (taR.Type == 0)
                {
                    if (gameEngine.D.Next(1, 10) == 3)
                        taR.AI();
                    if (gameEngine.D.Next(1, 100) % 30 == 0)
                        taR.ShootByRobot();
                }
            }

            //------------update RobotBoss--------------------
            if(gameEngine.RobotBoss!=null)
            {
                if (gameEngine.RobotBoss.Life)
                {
                    if (gameEngine.D.Next(1, 8) == 3)
                        gameEngine.RobotBoss.AI();
                        //gameEngine.RobotBoss.MoveByRobotTank();
                    if (gameEngine.D.Next(1, 6)==4 )
                        gameEngine.RobotBoss.ShootByRobotBoss();
                    
                   
                }
            }
        }

        public override void Update()
        {
            gameEngine.PlayerBullets.RemoveAll(DeletPlayerBullets);
            gameEngine.RobotBullets.RemoveAll(DeletRobotBullets);

            gameEngine.TankRobots.RemoveAll(DeleteTankRobots);

            gameEngine.Explodes.RemoveAll(DeleteExplodes);

            gameEngine.Walls.RemoveAll(DeleteWalls);
        }

        #region use predicate<>match to delete some matched element from list, in fact, this match is just a delegate
        private bool DeleteWalls(Wall obj)
        {
            if (obj.WallLife == false)
                return true;
            return false;
        }

        private bool DeleteExplodes(Explorer obj)
        {
            if (obj.ExplodeLife== false)
                return true;
            return false;
        }

        private bool DeleteTankRobots(TankRobot obj)
        {
            if (obj.Life == false)
                return true;
            return false;
        }

        private bool DeletRobotBullets(Bullet obj)
        {
            if (obj.Life == false)
                return true;
            return false;
        }

        private bool DeletPlayerBullets(Bullet obj)
        {
            if (obj.Life == false)
                return true;
            return false;
        }

        #endregion

        private bool iskeydownToMove=false;
        private int movecount=0;
        public  bool IsKeyDownToMove
        {
            get { return iskeydownToMove; }
            set { iskeydownToMove = value; }
        }
        public int MoveCount
        {
            get { return movecount; }
            set { movecount = value; }
        }


        public override void Render(Graphics g)
        {
            /*
             * As soon as mentioning render,there are two things very important.
             * The one is the location of all objects to creat a smooth animation,
             * another is  the order of all objects needed to be rendered, because
             * this order determines UI presented to User. What image or graphics should
             * be upper and which should be set to the bottom literally have a impact on
             * paints' quality, so it must be designed more carefully.
             * 
             * the following is the order of render:
             *     1.walls(reWall,river)
             *     2.RobotBullets
             *     3.PlayersBullets
             *     4.RobotTanks
             *     5.PlayerTank
             *     6.robotBoss
             *     7.explode
             *     8.walls(grass,steel,base)
             */

            /**********repaint the walls************/
            foreach (Wall w in gameEngine.Walls)
            {
                if (w.WallLife)
                {
                    if (w.WallType== 3||w.WallType==0)
                        g.DrawImage(gameEngine.Iwalls[w.WallType], w.WallLeft, w.WallTop, Constant.WallWidth, Constant.WallHeight);
                 
                }
            }

            /**********repaint the RobotBullets*************/
            foreach(Bullet b in gameEngine.RobotBullets)
            {
                if (b.Life)
                    g.DrawImage(gameEngine.Ibomb,(float)b.Left,(float)b.Top,Constant .bombWidth,Constant .bombHeight);
            }

            /************repaint the PlayerBullets************/
            foreach(Bullet b in gameEngine.PlayerBullets)
            {
                if (b.Life)
                {
                    g.DrawImage(gameEngine.Ibomb, (float)b.Left, (float)b.Top, Constant.bombWidth, Constant.bombHeight);
                }
            }
             
            /******repaint the RobotTanks*******/
            foreach(TankRobot taR in gameEngine.TankRobots)
            {
                if (taR.Life)
                {
                    int dir;
                    switch (taR.Direction)
                    {
                        case MoveDirection.UP: dir = 0; break;
                        case MoveDirection.DOWN: dir = 1; break;
                        case MoveDirection.LEFT: dir = 2; break;
                        case MoveDirection.RIGHT: dir = 3; break;
                        default: dir = 9999; break; //unpossibly to run here, its purpose is only to get codes permission of the compiler
                    }

                    g.DrawImage(gameEngine.Itank_robot[dir], (int)taR.Left , (int)taR.Top , Constant.tankWidth, Constant.tankHeight);
                }
            }

            /*************repaint the playerTanks****************/
            if(gameEngine.MyTank!=null&&gameEngine.MyTank.Life)
            {
                if (iskeydownToMove == true)
                {
                  g.DrawImage(gameEngine.Itank_player[(int)gameEngine.MyTank.Direction], (int)gameEngine.MyTank.Left, (int)gameEngine.MyTank.Top, Constant.tankWidth, Constant.tankHeight);
                    gameEngine.MyTank.Move();
                    movecount++;
                }
                if (movecount != Constant.TankPlayerSpeed/5)
                {
                    g.DrawImage(gameEngine.Itank_player[(int)gameEngine.MyTank.Direction], (int)gameEngine.MyTank.Left, (int)gameEngine.MyTank.Top, Constant.tankWidth, Constant.tankHeight);
                }
                else
                {
                    iskeydownToMove = false;
                    movecount = 0;
                }
            }

            /*************repaint the robotBoss******************/
            if(gameEngine.RobotBoss!=null&&gameEngine.RobotBoss.Life==true)
            {
                g.DrawImage(gameEngine.Irobot_boss[(int)gameEngine.RobotBoss.Direction], (float)gameEngine.RobotBoss.Left,(float)gameEngine.RobotBoss.Top,Constant.tankWidth,Constant.tankHeight);
            }
             
           /************repaint the explodes**********************/
            foreach (Explorer ex in gameEngine.Explodes)
            {
                if (ex.showtimes >= 8) { ex.ExplodeLife = false;  }
                else
                {
                    if (ex.ExplodeType == 0)
                        g.DrawImage(gameEngine.Iexplode[ex.showtimes], (float)ex.X, (float)ex.Y, Constant.ExplodexSize, Constant.ExplodexSize);
                    else
                        g.DrawImage(gameEngine.Iexplode[ex.showtimes], (float)ex.X, (float)ex.Y, Constant.ExplodeHitWallSize, Constant.ExplodeHitWallSize);
                    ex.showtimes++;
                }

                
            }

            /**********repaint the walls************/
            foreach (Wall w in gameEngine.Walls)
            {
                if (w.WallLife)
                {
                    if (w.WallType != 4&&w.WallType!=3&&w.WallType!=0)
                        g.DrawImage(gameEngine.Iwalls[w.WallType], w.WallLeft, w.WallTop, Constant.WallWidth, Constant.WallHeight);
                    else if (w.WallType == 4)
                    {
                        if (gamestate == false)
                        {
                            /*
                             *  this is two GDI to display tank and base's destruction situation when they are destroyed
                             */ 
                            g.DrawImage(gameEngine.Iexplode[7],(float)gameEngine.MyTank.Left,(float)gameEngine.MyTank .Top,Constant .tankWidth,Constant.tankHeight); 
                            g.DrawImage(gameEngine.Idestroy, w.WallLeft, w.WallTop, Constant.GrassSize, Constant.GrassSize);
                            
                        }
                        else
                            g.DrawImage(gameEngine.Iwalls[w.WallType], w.WallLeft, w.WallTop, Constant.GrassSize, Constant.GrassSize);
                    }
                }
            }
            
        }

        public bool GameState
        {
            get { return gamestate; }
            set { gamestate = value; }
        }

        public GameGDI GameEngine
        {
            get { return gameEngine; }
            set { gameEngine = value; }
        }

        public Collision Collision
        {
            get { return collision; }
        }
    }
}
